home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / bing-1.1.3.lha / bing-1.1.3 / src / win32 / icmp_win32.c < prev    next >
C/C++ Source or Header  |  1997-06-06  |  9KB  |  306 lines

  1. /*
  2.  * This module provides an interface to send and receive ICMP messages
  3.  * which is closer to the way Unix programs are written than the standard
  4.  * WIN32 icmp dll's interface.
  5.  */
  6.  
  7.  
  8. #include "win32/win32.h"
  9. #include <winsock.h>
  10. #include "win32/types.h"
  11.  
  12. #include "netinet/ip.h"
  13. #include "netinet/ip_var.h"
  14. #include "netinet/ip_icmp.h"
  15.  
  16. #include <ipexport.h>
  17. #include <icmpapi.h>
  18.  
  19. #include "mod_icmp.h"
  20.  
  21. #include <malloc.h>
  22. #include <errno.h>
  23.  
  24. typedef struct {
  25.         HANDLE            hICMP;        /* The ICMP dll handle */
  26.  
  27.         /* "Socket" options */
  28.         int            rcvbufsize;    /* Size of the receive buffer */
  29.         struct ip_option_information ip_options;/* The IP options */
  30.         unsigned long        timeout;    /* Time to wait for a reply */
  31.  
  32.         /* A few things to remember about the request */
  33.         u_short            msg_id;
  34.         u_short            msg_seq;
  35.  
  36.         /* Some fields to process the answers */
  37.         struct icmp_echo_reply* rcvbuf;        /* The buffer in which */
  38.                             /* IcmpSendEcho will store the answers */
  39.         int            nb_replies;    /* -1 => message not sent yet. */
  40.                                     /* >=0 => number of reply messages */
  41.         struct icmp_echo_reply*    current;    /* Pointer to next reply */
  42.  
  43.         LARGE_INTEGER rtt_in_ticks;        /* This is our own measurment of the RTT */
  44.         LARGE_INTEGER ticks_freq;
  45.     } icmp_state_i;
  46.  
  47. #define handle2state(h)        ((icmp_state_i*)h)
  48.  
  49. icmp_handle icmp_open()
  50. {
  51.     icmp_state_i* handle;
  52.  
  53.     /* Perform some initialisation to ease error recovery */
  54.     handle=NULL;
  55.  
  56.     /* Give a higher priority so that bing has better 
  57.      * chances not to be delayed when measuring the RTT.
  58.      */
  59.     SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
  60.  
  61.     /* Allocate the handle */
  62.     handle=malloc(sizeof(icmp_state_i));
  63.  
  64.     /* Fill defaults */
  65.     handle->hICMP=IcmpCreateFile();
  66.     handle->rcvbufsize=4096;
  67.     handle->rcvbuf=NULL;
  68.     handle->nb_replies=-1;
  69.     QueryPerformanceFrequency(&handle->ticks_freq);
  70.  
  71.     /* Set options defaults */
  72.     handle->ip_options.Ttl=255;
  73.     handle->ip_options.Tos=0;
  74.     handle->ip_options.Flags=0;
  75.     handle->ip_options.OptionsSize=0;
  76.     handle->ip_options.OptionsData=NULL;
  77.     return (icmp_handle)handle;
  78.  
  79. error:
  80.     if (handle!=NULL)
  81.         free(handle);
  82.     return NULL;
  83. }
  84.  
  85. int icmp_set_option(icmp_handle handle, int level, int optname, char* optval,
  86.                            int optlen)
  87. {
  88.     int ret;
  89.  
  90.     ret=0;
  91.     switch (level) {
  92.     case IPPROTO_IP:
  93.             /* The IP options are handled by building the 
  94.              * corresponding IP structure by hand.
  95.              */
  96.             /* No IP option is supported yet */
  97.             errno=ENOSYS;
  98.             ret=-1;
  99.         break;
  100.     case SOL_SOCKET:
  101.         switch (optname) {
  102.         case SO_RCVBUF:
  103.             handle2state(handle)->rcvbufsize=*((int*)optval);
  104.             break;
  105.         default:
  106.             errno=ENOSYS;
  107.             ret=-1;
  108.             break;
  109.         }
  110.         break;
  111.     default:
  112.         errno=ENOSYS;
  113.         ret=-1;
  114.     }
  115.  
  116.     return ret;
  117. }
  118.  
  119. void icmp_set_timeout(icmp_handle handle,unsigned long timeout)
  120. {
  121.     handle2state(handle)->timeout=timeout/1000;
  122. }
  123.  
  124. unsigned short icmp_get_id(icmp_handle handle)
  125. {
  126.     return handle2state(handle)->msg_id;
  127. }
  128.  
  129. int icmp_send(icmp_handle handle, char* msg, int msg_size, 
  130.               struct sockaddr* to_addr, int to_addr_size)
  131. {
  132.     DWORD reply_size;
  133.     LARGE_INTEGER start,stop;
  134.     static int nb_toohigh=0,nb=0;
  135.     static int icmp_min=1000000,query_min=1000000;
  136.  
  137.     /* Record some information for the recv */
  138.     handle2state(handle)->msg_id=((struct icmp*)msg)->icmp_id;
  139.     handle2state(handle)->msg_seq=((struct icmp*)msg)->icmp_seq;
  140.  
  141.     /* allocate the buffer for the replies */
  142.     handle2state(handle)->rcvbuf=realloc(handle2state(handle)->rcvbuf,
  143.         handle2state(handle)->rcvbufsize);
  144.  
  145.     QueryPerformanceCounter(&start);
  146.     handle2state(handle)->nb_replies=IcmpSendEcho(
  147.         handle2state(handle)->hICMP,
  148.         *((IPAddr*)&(((struct sockaddr_in*)to_addr)->sin_addr)),
  149.         msg+ICMP_MINLEN,
  150.         (WORD)(msg_size-ICMP_MINLEN),
  151.         &handle2state(handle)->ip_options,
  152.         handle2state(handle)->rcvbuf,
  153.         handle2state(handle)->rcvbufsize,
  154.         handle2state(handle)->timeout
  155.         );
  156.     QueryPerformanceCounter(&stop);
  157.     if ((handle2state(handle)->ticks_freq.QuadPart!=0) && 
  158.         (handle2state(handle)->nb_replies==1)) {
  159.         /* If we have a high performance counter, use it to measure 
  160.          * the RTT. The high performance counter will either give us 
  161.          * a much more precise measure of the RTT than the ICMP 
  162.          * library or it will give us a gross exageration of the RTT 
  163.          * if the execution of our process has been delayed by the 
  164.          * scheduler. Statistically this should give much better 
  165.          * results than the ICMP library (which tends to sometimes 
  166.          * under-estimate the RTT by up to nearly 2 ms which is 
  167.          * BAD in our case.
  168.          */
  169.         handle2state(handle)->rtt_in_ticks.QuadPart=
  170.             stop.QuadPart-start.QuadPart;
  171.     } else
  172.         handle2state(handle)->rtt_in_ticks.QuadPart=0;
  173.  
  174.     if (handle2state(handle)->nb_replies==0) {
  175.         if (GetLastError()==IP_REQ_TIMED_OUT)
  176.             return 0;
  177.         printf("icmp_send: error %d\n",GetLastError());
  178.         errno=GetLastError();
  179.         return -1;
  180.     }
  181.     handle2state(handle)->current=handle2state(handle)->rcvbuf;
  182.     return msg_size;
  183. }
  184.  
  185. int icmp_recv(icmp_handle handle, char* buffer, int buffer_size,
  186.               struct sockaddr* from_addr, int* from_addr_size, 
  187.               double* elapsed)
  188. {
  189.     if (handle2state(handle)->nb_replies>0) {
  190.         struct ip*    ip_msg;
  191.         struct icmp*    icmp_msg;
  192.  
  193.         /* Misc return values */
  194.         ((struct sockaddr_in*)from_addr)->sin_family=AF_INET;
  195.         ((struct sockaddr_in*)from_addr)->sin_port=0;
  196.         memcpy(&(((struct sockaddr_in*)from_addr)->sin_addr),
  197.             &handle2state(handle)->current->Address,4);
  198.         if (handle2state(handle)->rtt_in_ticks.QuadPart==0)
  199.             *elapsed=(double)(handle2state(handle)->current->RoundTripTime);
  200.         else
  201.             *elapsed=((double)(handle2state(handle)->rtt_in_ticks.QuadPart*1000))/
  202.                 handle2state(handle)->ticks_freq.QuadPart;
  203.  
  204.         /* Reconstruct the ip header */
  205.         ip_msg=(struct ip*)buffer;
  206.         ip_msg->ip_v=4;
  207.         ip_msg->ip_hl=(sizeof(struct ip)
  208.             +handle2state(handle)->current->Options.OptionsSize) >> 2;
  209.         ip_msg->ip_tos=handle2state(handle)->current->Options.Tos;
  210.         ip_msg->ip_len=((ip_msg->ip_hl) << 2)
  211.             +ICMP_MINLEN
  212.             +handle2state(handle)->current->DataSize;
  213.         ip_msg->ip_id=0;
  214.         ip_msg->ip_off=0;
  215.         ip_msg->ip_ttl=handle2state(handle)->current->Options.Ttl;
  216.         ip_msg->ip_p=0;
  217.         ip_msg->ip_sum=0;
  218.         memcpy(&(ip_msg->ip_src),&handle2state(handle)->current->Address,4);
  219.         memset(&ip_msg->ip_dst,0,4);
  220.         if (handle2state(handle)->current->Options.OptionsSize>0)
  221.             memcpy(buffer+sizeof(struct ip),
  222.                 handle2state(handle)->current->Options.OptionsData,
  223.                 handle2state(handle)->current->Options.OptionsSize);
  224.  
  225.         /* Reconstruct the icmp header */
  226.         icmp_msg=(struct icmp*)(buffer+((ip_msg->ip_hl) << 2));
  227.         switch (handle2state(handle)->current->Status) {
  228.         /* Echo Reply (what we expect) */
  229.         case IP_SUCCESS:
  230.             icmp_msg->icmp_type=0;
  231.             icmp_msg->icmp_code=0;
  232.             icmp_msg->icmp_id=handle2state(handle)->msg_id;
  233.             icmp_msg->icmp_seq=handle2state(handle)->msg_seq;
  234.             break;
  235.  
  236.         /* Destination Unreachable */
  237.         case IP_DEST_NET_UNREACHABLE:
  238.             icmp_msg->icmp_type=3;
  239.             icmp_msg->icmp_code=0;
  240.             break;
  241.         case IP_DEST_HOST_UNREACHABLE:
  242.             icmp_msg->icmp_type=3;
  243.             icmp_msg->icmp_code=1;
  244.             break;
  245.         case IP_DEST_PROT_UNREACHABLE:
  246.             icmp_msg->icmp_type=3;
  247.             icmp_msg->icmp_code=2;
  248.             break;
  249.         case IP_DEST_PORT_UNREACHABLE:
  250.             icmp_msg->icmp_type=3;
  251.             icmp_msg->icmp_code=3;
  252.             break;
  253.  
  254.         /* Time Exceeded */
  255.         case IP_TTL_EXPIRED_TRANSIT:
  256.             icmp_msg->icmp_type=11;
  257.             icmp_msg->icmp_code=0;
  258.             break;
  259.         case IP_TTL_EXPIRED_REASSEM:
  260.             icmp_msg->icmp_type=11;
  261.             icmp_msg->icmp_code=1;
  262.             break;
  263.  
  264.         /* Parameter Problem */
  265.         case IP_PARAM_PROBLEM:
  266.             icmp_msg->icmp_type=12;
  267.             icmp_msg->icmp_code=0;
  268.             /* how can I get a value for the pointer field ? */
  269.             break;
  270.  
  271.         /* Source Quench */
  272.         case IP_SOURCE_QUENCH:
  273.             icmp_msg->icmp_type=4;
  274.             icmp_msg->icmp_code=0;
  275.             break;
  276.  
  277.         default:
  278.             handle2state(handle)->nb_replies--;
  279.             handle2state(handle)->current++;
  280.             return -handle2state(handle)->current->Status;
  281.         }
  282.  
  283.         /* Who cares about the checksum ? */
  284.         icmp_msg->icmp_cksum=0;
  285.  
  286.         /* Copy data */
  287.         memcpy(buffer+((ip_msg->ip_hl) << 2)+ICMP_MINLEN,
  288.             handle2state(handle)->current->Data,
  289.             handle2state(handle)->current->DataSize);
  290.  
  291.         handle2state(handle)->nb_replies--;
  292.         handle2state(handle)->current++;
  293.         return ip_msg->ip_len;
  294.     } else
  295.         return 0;
  296. }
  297.  
  298. int icmp_close(icmp_handle handle)
  299. {
  300.     int ret;
  301.  
  302.     ret=IcmpCloseHandle((HANDLE)(((icmp_state_i*)handle)->hICMP));
  303.     free(handle);
  304.     return (ret?0:-1);
  305. }
  306.